package ge.telasi.tasks.ui.comp;

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Calendar;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import static java.util.Calendar.*;
import static java.awt.Color.*;

/**
 * Grid for date display.
 *
 * @author dimitri
 */
public class CalendarGrid extends JPanel {
    public static final String[] DAYS = {"ორ.", "სმ.", "ოთ.", "ხთ.", "პრ.", "შბ.", "კვ."};
    public static final int[] DAYS_NUM = {Calendar.MONDAY, Calendar.TUESDAY,
        Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SATURDAY,
        Calendar.SUNDAY};
    private DateLabel labels[] = new DateLabel[42];

    private Calendar date;

    private CalendarControl fCalendar;

    public void setFCalendar(CalendarControl fCalendar) {
        this.fCalendar = fCalendar;
    }

    public CalendarControl getFCalendar() {
        return fCalendar;
    }

    public CalendarGrid() {
        // initialzie UI components
        initComponents();

        // set current date
        setDate(null);
    }

    private void initComponents() {
        setLayout(new GridLayout(7, 7, 2, 2));
        // week-day header labels
        for (int i = 0; i < 7; i++) {
            JLabel lbl = new JLabel(DAYS[i]);
            lbl.setOpaque(true);
            lbl.setBackground(Color.RED);
            lbl.setForeground(Color.WHITE);
            lbl.setHorizontalAlignment(JLabel.CENTER);
            add(lbl);
        }
        // month-day variable labels
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 7; j++) {
                DateLabel dateLabel = new DateLabel();
                dateLabel.setOpaque(true);
                dateLabel.setBackground(Color.WHITE);
                labels[i * 7 + j] = dateLabel;
                dateLabel.setHorizontalAlignment(JLabel.RIGHT);
                add(dateLabel);
                dateLabel.addMouseListener(new MouseAdapter() {
                    @Override
                    public void mouseClicked(MouseEvent evnt) {
                        DateLabel clicked = (DateLabel) evnt.getSource();
                        if (clicked.getDate() != null && getFCalendar() != null) {
                            getFCalendar().setDate(clicked.getDate());
                        }
                    }

                });
            }
        }
    }

    public Calendar getDate() {
        return date;
    }

    public void setDate(Calendar date) {
        this.date = date;
        reset();
    }

    private void reset() {
        if (date == null) {
            date = Calendar.getInstance();
        }
        int indexOfFirst = getIndexOfFirst(date);
        Calendar first = getFirstOfMonth(date);
        first.add(DAY_OF_MONTH, -indexOfFirst);
        for (DateLabel lbl : labels) {
            lbl.setSelection(date);
            lbl.setDate(first);
            lbl.reset();
            first.add(DAY_OF_MONTH, 1);
        }

    }

    int getIndexOfFirst(Calendar cal) {
        Calendar first = getFirstOfMonth(date);
        int dayOfWeek = first.get(Calendar.DAY_OF_WEEK);
        for (int i = 0; i < DAYS_NUM.length; i++) {
            if (dayOfWeek == DAYS_NUM[i]) {
                return i;
            }
        }
        return -1;
    }
    
    Calendar getFirstOfMonth(Calendar cal) {
        int year = date.get(Calendar.YEAR);
        int month = date.get(Calendar.MONTH);
        Calendar first = Calendar.getInstance();
        first.set(Calendar.YEAR, year);
        first.set(Calendar.MONTH, month);
        first.set(Calendar.DATE, 1);
        return first;
    }

    /**
     * Label for displaying day of the date.
     */
    static class DateLabel extends JLabel {
        private Calendar date;
        private Calendar selection;

        public Calendar getDate() {
            return date;
        }

        public void setDate(Calendar date) {
            Calendar cal = getInstance();
            cal.set(YEAR, date.get(YEAR));
            cal.set(MONTH, date.get(MONTH));
            cal.set(DAY_OF_MONTH, date.get(DAY_OF_MONTH));
            this.date = cal;
        }

        public Calendar getSelection() {
            return selection;
        }

        public void setSelection(Calendar selection) {
            this.selection = selection;
        }

        public void reset() {
            if (date == null || selection == null) {
                return;
            }
            setText(String.valueOf(date.get(DAY_OF_MONTH)));
            boolean sameDay = date.get(DAY_OF_MONTH) == selection.get(DAY_OF_MONTH);
            boolean sameMonth = date.get(MONTH) == selection.get(MONTH);
            if (sameDay && sameMonth) {
                setBackground(BLUE);
                setForeground(WHITE);
            } else if (sameMonth) {
                setBackground(new Color(255, 255, 230));
                setForeground(BLACK);
            } else {
                setBackground(WHITE);
                setForeground(GRAY);
            }
            if (isToday()) {
                setBorder(BorderFactory.createLineBorder(Color.RED, 1));
            } else {
                setBorder(null);
            }
        }

        public boolean isToday() {
            Calendar now = getInstance();
            return now.get(YEAR) == date.get(YEAR) &&
                    now.get(MONTH) == date.get(MONTH) &&
                    now.get(DAY_OF_MONTH) == date.get(DAY_OF_MONTH);
        }

    }

}
